/*
 * $Id*
 */
package org.crazydays.text;


import java.io.Serializable;
import java.text.ParseException;
import java.util.List;
import java.util.ArrayList;

/**
 * Argument
 */
public class Argument
	implements Serializable
{
	/** serial version uid */
	public final static long serialVersionUID = "$Id$".hashCode();

	/** string */
	protected String string;

	/** character */
	protected Character character;

	/** required */
	protected boolean required;

	/** options */
	protected List<String> options = new ArrayList<String>();

	/** value */
	protected String value;

	/**
	 * Argment constructor.
	 *
	 * @param string String
	 * @param character Character
	 */
	public Argument(String string, Character character)
	{
		setString(string);
		setCharacter(character);
	}

	/**
	 * Argument constructor.
	 *
	 * @param string String
	 * @param character Character
	 * @param required Required
	 */
	public Argument(String string, Character character, boolean required)
	{
		setString(string);
		setCharacter(character);
		setRequired(required);
	}

	/**
	 * Argument constructor.
	 *
	 * @param string String
	 * @param character Character 
	 * @param required Required
	 * @param options Options
	 */
	public Argument(String string, Character character, boolean required, List<String> options)
	{
		setString(string);
		setCharacter(character);
		setRequired(required);
		setOptions(options);
	}

	/**
	 * Set string.
	 *
	 * @param string String
	 */
	public void setString(String string)
	{
		this.string = string;
	}

	/**
	 * Get string.
	 *
	 * @return String
	 */
	public String getString()
	{
		return string;
	}

	/**
	 * Set character.
	 *
	 * @param character Character
	 */
	public void setCharacter(Character character)
	{
		this.character = character;
	}

	/**
	 * Get character.
	 *
	 * @return Character
	 */
	public Character getCharacter()
	{
		return character;
	}

	/**
	 * Set required.
	 *
	 * @param required Required
	 */
	public void setRequired(boolean required)
	{
		this.required = required;
	}

	/**
	 * Get required.
	 *
	 * @return Required
	 */
	public boolean getRequired()
	{
		return required;
	}

	/**
	 * Set options.
	 *
	 * @param options Options
	 */
	public void setOptions(List<String> options)
	{
		for (String option : options) {
			addOption(option);
		}
	}

	/**
	 * Get options.
	 *
	 * @return Options
	 */
	public List<String> getOptions()
	{
		return options;
	}

	/**
	 * Add option.
	 *
	 * @param option Option
	 */
	public void addOption(String option) {
		getOptions().add(option);
	}

	/**
	 * Set value.
	 *
	 * @param Value
	 */
	public void setValue(String value)
	{
		this.value = value;
	}

	/**
	 * Get value.
	 *
	 * @return Value
	 */
	public String getValue()
	{
		return value;
	}

	/**
	 * Get value as integer.
	 *
	 * @return Value
	 * @throws ParseException
	 */
	public int getValueAsInteger()
		throws ParseException
	{
		return Integer.parseInt(getValue());
	}

	/**
	 * Get value as long.
	 *
	 * @return Value
	 * @throws ParseException
	 */
	public long getValueAsLong()
		throws ParseException
	{
		return Long.parseLong(getValue());
	}

	/**
	 * Get value as float.
	 *	
	 * @return Value
	 * @throws ParseException
	 */
	public float getValueAsFloat()
		throws ParseException
	{
		return Float.parseFloat(getValue());
	}

	/**
	 * Get value as double.
	 *
	 * @return Value
	 * @throws ParseException
	 */
	public double getValueAsDouble()
		throws ParseException
	{
		return Double.parseDouble(getValue());
	}

	/**
	 * Validate argument.
	 *
	 * @throws ArgumentException
	 */
	public void validate()
		throws ArgumentException
	{
		if (getRequired() && getValue() == null) {
			throw new ArgumentException("Value required").
				setArgument(this);
		}

		if (getValue() != null && getOptions().size() > 0) {
			boolean validOption = false;

			for (String option : getOptions()) {
				if (option.equals(getValue())) {
					validOption = true;
				}
			}

			if (!validOption) {
				throw new ArgumentException("Invalid option: " +
					getValue()).setArgument(this);
			}
		}
	}

	/**
	 * Clear value.
	 */
	public void clearValue()
	{
		setValue(null);
	}

	/**
	 * Equals.
	 *
	 * @param o Object
	 * @return Equals
	 * @see #Object.equals(Object)
	 */
	public boolean equals(Object o)
	{
		String string = getString();
		Character character = getCharacter();

		if (o instanceof String) {
			if (string == null) {
				return false;
			} else {
				return string.equals(o);
			}
		} else if (o instanceof Character) {
			if (character == null) {
				return false;
			} else {
				return character.equals(o);
			}
		} else if (o instanceof Argument) {
			Argument argument = (Argument) o;

			String argumentString = argument.getString();
			Character argumentCharacter = argument.getCharacter();

			boolean stringEqual = false;
			if (argumentString == null && string == null) {
				stringEqual = true;
			} else {
				if (argumentString == null) {
					stringEqual = false;
				} else {
					stringEqual = argumentString.equals(string);
				}
			}

			boolean characterEqual = false;
			if (argumentCharacter == null && character == null) {
				characterEqual = true;
			} else {
				if (argumentCharacter == null) {
					characterEqual = false;
				} else {
					characterEqual = argumentCharacter.equals(character);
				}
			}

			return stringEqual && characterEqual;
		} else {
			return false;
		}
	}

	/**
	 * Hash code.
	 *
	 * @return Hash code
	 * @see #Object.hashCode()
	 */
	public int hashCode()
	{
		StringBuffer buffer = new StringBuffer();

		String string = getString();
		if (string != null) {
			buffer.append(string);
		}

		buffer.append('\0');

		Character character = getCharacter();
		if (character != null) {
			buffer.append(character);
		}

		return buffer.hashCode();
	}

	/**
	 * ToString.
	 *
	 * @return String
	 * @see Object#toString()
	 */
	public String toString()
	{
		StringBuffer buffer = new StringBuffer();

		buffer.append("string: ");
		String string = getString();
		if (string != null) {
			buffer.append(string);
		}

		buffer.append(" character: ");
		Character character = getCharacter();
		if (character != null) {
			buffer.append(character);
		}

		buffer.append(" required: ");
		buffer.append(getRequired());

		buffer.append(" value: ");
		String value = getValue();
		if (value != null) {
			buffer.append(value);
		}

		return buffer.toString();
	}
}
